﻿//MarketDepthPair.cs
//Copyright (c) 2013 StockSharp LLC, all rights reserved.
//This code module is part of StockSharp library.
//This code is licensed under the GNU GENERAL PUBLIC LICENSE Version 3.
//See the file License.txt for the license details.
//More info on: http://stocksharp.com

namespace StockSharp.BusinessEntities
{
	using System;
	using System.ComponentModel;

	using Ecng.Common;
	using Ecng.Serialization;

	using Xceed.Wpf.Toolkit.PropertyGrid.Attributes;

	/// <summary>
	/// Пара котировок.
	/// </summary>
	[System.Runtime.Serialization.DataContract]
	[Serializable]
	[Ignore(FieldName = "IsDisposed")]
	public class MarketDepthPair : Equatable<MarketDepthPair>
	{
		private readonly bool _isFull;

		/// <summary>
		/// Создать пару котировок.
		/// </summary>
		/// <param name="security">Инструмент.</param>
		/// <param name="bid">Бид.</param>
		/// <param name="ask">Оффер.</param>
		public MarketDepthPair(Security security, Quote bid, Quote ask)
		{
			if (security == null)
				throw new ArgumentNullException("security");

			if (bid != null && bid.OrderDirection != OrderDirections.Buy)
				throw new ArgumentException("Бид может быть только на покупку.");

			if (ask != null && ask.OrderDirection != OrderDirections.Sell)
				throw new ArgumentException("Оффер может быть только на продажу.");

			Security = security;
			Bid = bid;
			Ask = ask;

			_isFull = bid != null && ask != null;
		}

		/// <summary>
		/// Инструмент.
		/// </summary>
		public Security Security { get; private set; }

		/// <summary>
		/// Бид.
		/// </summary>
		[DisplayName("Бид")]
		[Description("Котировка на покупку.")]
		[ExpandableObject]
		public Quote Bid { get; private set; }

		/// <summary>
		/// Оффер.
		/// </summary>
		[DisplayName("Оффер")]
		[Description("Котировка на продажу.")]
		[ExpandableObject]
		public Quote Ask { get; private set; }

		/// <summary>
		/// Размер спреда по цене.
		/// </summary>
		[DisplayName("Спред по цене")]
		[Description("Размер спреда по цене.")]
		public decimal SpreadPrice
		{
			get { return _isFull ? Ask.Security.ShrinkPrice(Ask.Price - Bid.Price) : 0; }
		}

		/// <summary>
		/// Размер спреда по объему. Если значение отрицательное, значит лучший оффер имеет больший объем, чем лучший бид.
		/// </summary>
		[DisplayName("Спреда по объему.")]
		[Description("Размер спреда по объему. Если значение отрицательное, значит лучший оффер имеет больший объем, чем лучший бид.")]
		public decimal SpreadVolume
		{
			get { return _isFull ? (Ask.Volume - Bid.Volume).Abs() : 0; }
		}

		/// <summary>
		/// Середина спреда.
		/// </summary>
		[DisplayName("Спред")]
		[Description("Середина спреда.")]
		public decimal MiddlePrice
		{
			get { return _isFull ? (Bid.Price + SpreadPrice / 2) : 0; }
		}

		/// <summary>
		/// Создать копию пары котировок.
		/// </summary>
		/// <returns>Копия.</returns>
		public override MarketDepthPair Clone()
		{
			return new MarketDepthPair(Security, Bid.CloneNullable(), Ask.CloneNullable());
		}

		/// <summary>
		/// Сравнить две пары котировок на эквивалентность. 
		/// </summary>
		/// <param name="other">Другая пара котировок, с которой необходимо сравнивать.</param>
		/// <returns>True, если другая пара котировок равна текущей, иначе false.</returns>
		protected override bool OnEquals(MarketDepthPair other)
		{
			return Bid == other.Bid && Ask == other.Ask;
		}

		/// <summary>
		/// Получить строковое представление.
		/// </summary>
		/// <returns>Строковое представление.</returns>
		public override string ToString()
		{
			return "{{{0}}} {{{1}}}".Put(Bid, Ask);
		}

		/// <summary>
		/// Рассчитать хеш-код объекта <see cref="MarketDepthPair"/>.
		/// </summary>
		/// <returns>Хеш-код.</returns>
		public override int GetHashCode()
		{
			return (Bid != null ? Bid.GetHashCode() : 0) ^ (Ask != null ? Ask.GetHashCode() : 0);
		}
	}
}